<script src="/js/functions.js"></script>
<script src="/js/utils.js"></script>
<script>

var lex_rule = function(str, f) {
	var out = [];
	var i, max = str.length;
	for (i = 0; i < max; ++i)
		out[i] = {};
	var action = function() { f(str) };
	action.toString = function() { return '[' + str + ']' };
	out[out.length] = { action: action };
	for (i = 0, max = out.length - 1; i < max; ++i)
		out[i][str[i]] = out[i + 1];
	return out[0];
};

var last_rule_id = 0;
var last_state_id = 0;

var lex_regexp = function(str, f) {
	var out = [];
	var i, max = str.length;
	for (i = 0; i < max; ++i)
		out[i] = {};

	++last_rule_id;
	
	var action = function() { f && f(str) };
	action.toString = function() { return '[' + str + ']' };
	out[out.length] = {
		action: action,
		description: str + ' <b>&#8718;</b>'
	};

	var next, i, c, x;
	//console.dir(out);
	for (i = 0; i < max; ++i) {
		x = out[i];
		next = out[i + 1];
		c = str[i];
		switch (c) {
			default: x[c] = next; break;
			case '.': x.any = next; break;
		}
		x.description = str.substr(0, i) + '<b>.</b>' + str.substr(i);
	}

	for (i = 0, max = out.length; i < max; ++i) {
		out[i].id = ++last_state_id;
	}
	
	//console.dir(out[0]);
	//debugger;
	
	return out[0];
};


var lex_merge = function(r1, r2) {
	//if (r1.action)
	//	return r1;

	r2 = objoin({}, r2);
	if (r1.default_action) {
		for (var i in r2) {
			if (i.length > 1) continue;
			r2[i].action = r1.default_action;
		}
		delete r1.default_action;
	}
	//if (!r1.any && r2.any) {
	//	r1.any = r2.any;
	//}
	
	if (r2.action && !r1.action) {
		r1.default_action = r2.action;
	}
	
	if (r1.description && r2.description) {
		if (r1.action)
			r1.description += ' ' + r2.description.replace(/\|/g, r1.description);
		else
			r1.description += ' | ' + r2.description;
	} else if (!r1.description && r2.description)
		r1.description = r2.description;
	
	for (var i in r2) {
		if (i.length > 1 && i != 'any') continue;
		if (!r1[i]) {
			r1[i] = objoin({}, r2[i]);
			continue;
		}
		lex_merge(r1[i], r2[i]);
	}
	return r1;
};


var trace = function(x) {
	document.write('<pre>' + sprintf.apply(this, arguments) + '</pre>');
};


var lex_run = function(initial, input) {
	var state = initial;
	var c;
	//console.dir(state);
	var i = 0, max = input.length;
	yytext = '';
	var d;
	while (true) {
		if (i >= max) break;
				
		d = state.description ? state.description : 'Без описания';
		trace(d);
		
		if (state === initial)
			yytext = '';
		
		c = input[i];
		yytext += c;
		if (state[c]) {
			state = state[c];
			
		} else if (state.any) {
			state = state.any;
		} else {
			trace('&nbsp;&nbsp;"<b>%s</b>" &#8594;&nbsp;&nbsp;STOP', c);
			return;
		
			if (state.default_action)
				state.default_action();
			state = initial[c] || initial.any;
			yytext = c;
			if (!state) {
				state = initial;
				yytext = '';			
			}
		}
		++i;

		trace('&nbsp;&nbsp;"<b>' + c + '</b>" &#8594;&nbsp;&nbsp;' + (state.description ? state.description : 'Без описания'));
		trace('&nbsp;');

		if (state.action) {
			trace('Светрка: <b>%s</b><br><br><br>', yytext);
			state.action();
			yytext = '';
			state = initial;
		}
		
	}
	if (state.default_action)
		state.default_action();
};


var lex_normalize = function(r) {
	var initial = r;
	var buf = [r];
	var i = 0, j, max, x;
	buf[0].locked = true;
	do {
		for (max = buf.length; i < max; ++i) {
			x = buf[i];
			x.locked = true;
			for (j in x) {
				if (j.length != 1 && j != 'any') continue;
				if (x[j].locked) continue;
				if (!is_object(x[j])) continue;
				buf[buf.length] = x[j];
			}
		}
	} while (max < buf.length);
	for (i = 0, max = buf.length; i < max; ++i) {
		delete buf[i].locked;
	}
	buf.shift();
	//console.dir(buf);
	//debugger;

	for (i = 0, max = buf.length; i < max; ++i) {
		lex_merge(buf[i], initial);
		//buf[i].normalized = true;
	}

	
	
	for (i = 0, max = buf.length; i < max; ++i) {
		if (!buf[i].default_action) continue;
		for (j in buf[i]) {
			if (j.length != 1) continue;
			if (!buf[i][j].action)
				buf[i][j].default_action = buf[i].default_action;
		}
		delete buf[i].default_action;
	}
	
	
	return buf;
};


var test1 = function() {
	var r = {};
	lex_merge(r, lex_rule("ab"));
	lex_merge(r, lex_rule("a"));
	//var r2 = lex_rule("ab");
	//var r = lex_merge(r1, r2);
	lex_normalize(r);
	console.dir(r);
	//lex_parse(r1, "aab");
};

var test2 = function() {
	var r = { description: 'Начальное состояние' };
	
	lex_merge(r, lex_regexp("..a", function(x){
		//trace('Свертка текста %s', yytext);
	}));
	//lex_merge(r, lex_rule("a+"));
	//lex_normalize(r);
	//console.dir(r);
	lex_run(r, "yzzbaz");
};


var lex_dump = function(r) {
	trace('state %d:  %s', r.id, r.description);
	for (var i in r) {
		if (i.length != 1 && i != 'any') continue;
		lex_dump(r[i]);
	}
};


var test3 = function() {
	var r = { };
	r = lex_regexp("aa");
	lex_merge(r, lex_regexp("a"));
	lex_merge(r.a, lex_regexp("b"));
	//lex_merge(r, lex_regexp("a"));
	lex_dump(r);
	//lex_normalize(r);
	//lex_run(r, "aaa");
};



test3();




</script>















